package com.air.tools;

import com.air.beans.SearchResult;
import com.air.db.DbConnectionFactory;
import com.air.db.TableDao;
import com.air.listeners.StartSearchListener;
import com.air.ui.MainWindow;
import com.alibaba.fastjson.JSON;
import lombok.Data;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 创建执行搜索的线程工具类
 * @author Air
 * @since v1
 * @date 2018年11月21日14:38:39
 */
@Data
public class TaskFather {
    /**
     * 开始搜索
     */
    public void start(){
        //先查询出所有的表
        try {
            if(StringTools.isEmptyWithTrimOrNull(mw.getTextField_SearchText().getText() )){
                return;
            }
            final String input = mw.getTextField_SearchText().getText() .trim();
            PropertiesTools pro = PropertiesTools.getInstance();
            Connection conn = DbConnectionFactory.getConnection();
            Statement st = conn.createStatement();
            String sql = pro.getSqlQueryAllTableNames(pro.getDbType());
            if(StringTools.isEmptyWithTrimOrNull(sql)){
                startSearchListener.allFinalsh("   查询表名SQL语句错误!");
                return;
            }
            ResultSet rs = st.executeQuery(sql);
            ArrayList<String> tabs = new ArrayList<>(500);
            while(rs.next()){
                tabs.add(rs.getString(1));
            }
            if(tabs.size() < 1){
                startSearchListener.allFinalsh("  数据库没有任何用户表!");
                return;
            }
            results.clear();
            updateTable();
            isStop = false;
            int threadMax = pro.getThreadNum();
            calcSingleThreadTabNum(tabs.size(), threadMax);
            DbConnectionFactory.setMax(5);
            startSearchListener.setTotal(totalThread);
            threadPool = new ThreadPoolExecutor(totalThread,
                    totalThread +  1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(totalThread) );
            //开始实例化线程进行查询
            ArrayList<ArrayList<String>> threadsTabs = new ArrayList<>(totalThread);
            ArrayList<String> threadTabs ;
            for(int i = 0; i < totalThread; i++){
               threadTabs = new ArrayList<>(singleThreadTabNum);
               int index = i * singleThreadTabNum;
               if(index < tabs.size()){
                   for(int x = 0; x < singleThreadTabNum; x++){
                       if(index < tabs.size()){
                           threadTabs.add(tabs.get(index++));
                       }else{
                           break;
                       }
                   }
               }
               threadsTabs.add(threadTabs);
            }
            threadsTabs.stream().forEach( threadTableNameList -> {
                TableDao dao = new TableDao(this, startSearchListener
                        , threadTableNameList);
                dao.setFast(pro.isFastModel());
                threadPool.execute(()->{
                    dao.queryTableAllColumn(input);
                    addFinalsh();
                });
            });
            threadPool.shutdown();
            output.outLine("当前正在搜索中线程数: "  + threadPool.getActiveCount());
        } catch (SQLException e) {
            output.outLine(e.toString());
            startSearchListener.allFinalsh("    发生错误终止搜索: " + e.toString() );
            e.printStackTrace();
        }
    }

    private void addFinalsh() {
        if(threadPool.getActiveCount() > 0){
            output.outLine("当前正在搜索中线程数: "  + threadPool.getActiveCount());
        }else{
            output.outLine("所有线程已完成, 搜索完成! "   );
        }
        startSearchListener.addFinalsh(this);
    }

    /**
     * 计算 一共需要多少个进程, 每个进程分配多少数量
     * @param size
     * @param threadMax
     */
    private void calcSingleThreadTabNum(int size, int threadMax) {
        totalThread = threadMax;
        if(size <= threadMax){
            singleThreadTabNum = 1;
            totalThread = size;
        }
        int cf = size / threadMax;
        if(cf *  threadMax  ==  size){
            singleThreadTabNum = cf;
        }else{
            int moreEechThread = (  (size - (cf *  threadMax ) ) / threadMax );
            moreEechThread = moreEechThread == 0 ? 1 : moreEechThread + 1;
            singleThreadTabNum = cf +  moreEechThread;
        }
    }

    /**
     * 终止所有搜索线程
     */
    public void stopAll() {
        isStop = true;
    }

    public boolean isStop() {
        return isStop;
    }

    /**
     * 添加一个搜索结果
     * @param re
     */
    public synchronized  void addSearchResult(SearchResult re){
        results.add(re);
        updateTable();
    }

    /**
     * 根据搜索结果 更新表格UI
     */
    public void updateTable(){
        JTable table = mw.getTable();
        String[][] datas = getSearchDatas();
        DefaultTableModel model = new DefaultTableModel(datas, mw.getTableTitles());
        table.setModel(model);
        mw.setTableColumnSize();
        table.updateUI();
    }

    private String[][] getSearchDatas() {
        if(results.size() < 1){
            return new String[][]{};
        }
        String[][] re = new String[results.size()][4];
        for(int row = 0; row < results.size(); row++){
            re[row][0] = String.valueOf(row);
            re[row][1] = results.get(row).getTableName();
            re[row][2] = results.get(row).getColumName();
            re[row][3] = results.get(row).getSql();
        }
        return re;
    }

    public LinkedList<SearchResult> getResults() {
        return results;
    }

    public TaskFather(MainWindow mw, StartSearchListener startSearchListener) {
        this.mw = mw;
        this.startSearchListener = startSearchListener;
        this.results = new LinkedList<>();
    }
    private MainWindow mw;
    private StartSearchListener startSearchListener;
    private int singleThreadTabNum =1;
    private int totalThread = 1;
    private ThreadPoolExecutor threadPool;
    private LinkedList<SearchResult> results;
    private boolean isStop = false;
}
